package com.jeasonzhao.commons.inplacecache;

import java.util.Iterator;
import java.util.Map;

public abstract class AbstractCacheMap<K,V> implements ICache<K,V>
{
    private Map<K,CacheObject<K,V>> cacheMap = null; //Cache data
    private int cacheSize = 0; // max cache size, 0 = no limit
    private long timeout = 0; // default timeout, 0 = no timeout
    private boolean existCustomTimeout = false;
    public AbstractCacheMap()
    {

    }

    public AbstractCacheMap(int cs,long to,Map<K,CacheObject<K,V>> m)
    {
        this.cacheSize = cs;
        this.timeout = to;
        this.cacheMap = m;
    }
    public int getCacheSize()
    {
        return this.cacheSize;
    }

    protected Map<K,CacheObject<K,V>> getCacheMap()
    {
        return cacheMap;
    }

    public long getCacheTimeout()
    {
        return this.timeout;
    }

    protected boolean isPruneExpiredActive()
    {
        return(this.timeout != 0) || this.existCustomTimeout;
    }

    public void put(K key,V object)
    {
        put(key,object,this.timeout);
    }

    public void put(K key,V object,long timeout)
    {
        CacheObject<K,V> co = new CacheObject<K,V>(key,object,timeout);
        if(timeout != 0)
        {
            this.existCustomTimeout = true;
        }
        if(isFull())
        {
            prune();
        }
        if(null != this.cacheMap)
        {
            this.cacheMap.put(key,co);
        }
    }

    public V get(K key)
    {
        CacheObject<K,V> co = null == this.cacheMap ? null : this.cacheMap.get(key);
        if(co == null)
        {
            return null;
        }
        else if(co.isExpired() == true)
        {
            remove(key);
            return null;
        }
        else
        {
            return co.getObject();
        }
    }

    public Iterator<V> iterator()
    {
        return new CacheValuesIterator<V>(this);
    }

    public boolean isFull()
    {
        if(cacheSize == 0)
        {
            return false;
        }
        return cacheMap.size() >= cacheSize;
    }

    public void remove(K key)
    {
        if(null != this.cacheMap)
        {
            cacheMap.remove(key);
        }
    }

    public void clear()
    {
        if(null != this.cacheMap)
        {
            cacheMap.clear();
        }
    }

    public int size()
    {
        return null == this.cacheMap ? 0 : this.cacheMap.size();
    }

    public boolean isEmpty()
    {
        return size() == 0;
    }

    public abstract int prune();

    protected void setCacheMap(Map<K,CacheObject<K,V>> cacheMap)
    {
        this.cacheMap = cacheMap;
    }

    protected void setCacheSize(int cacheSize)
    {
        this.cacheSize = cacheSize;
    }

    protected void setCacheTimeout(long cacheTimeout)
    {
        this.timeout = cacheTimeout;
    }
}
